/*+***********************************************************************************
 Filename: 9k_mcu01_mycore_v01\src\mem\zh_sram_v01.v
 Description: sram with sync read/write and wmask implement by verilog.
   dout is change on pos-edge of clk with addr.
   data is update on pos-edge of clk when wen and wmask in effect.
              
 Modification:
   2025.08.17 Creation   H.Zheng

Copyright (C) 2025  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/

module zh_sram_v01 #(parameter RAM_SIZE_IN_KB=1)(
  input wire clk, //clock
  input wire ce,

  input wire [clogb2(RAM_SIZE_IN_KB*256-1)-1:0] addr,
  output wire [31:0] dout,

  input wire wclk, //write clock
	input wire wen, //write enable
  input  wire [3:0] wmask,
  input wire [31:0] din
);

  reg [7:0] BRAM0 [0:RAM_SIZE_IN_KB*256-1];
  reg [7:0] BRAM1 [0:RAM_SIZE_IN_KB*256-1];
  reg [7:0] BRAM2 [0:RAM_SIZE_IN_KB*256-1];
  reg [7:0] BRAM3 [0:RAM_SIZE_IN_KB*256-1];

  //read
  wire [7:0] dout0, dout1, dout2, dout3;


  reg [clogb2(RAM_SIZE_IN_KB*256-1)-1:0] addr_r;
  always @(posedge clk) begin
    if(ce) begin
      addr_r <= addr;
    end   
  end

  assign dout0 =  BRAM0[addr_r];
  assign dout1 =  BRAM1[addr_r];
  assign dout2 =  BRAM2[addr_r];
  assign dout3 =  BRAM3[addr_r];

  assign dout = {dout3, dout2, dout1, dout0};

  //write
  always @(posedge wclk) begin
    if(ce&wen&wmask[0])
      BRAM0[addr] <= din[7:0];
  end

  always @(posedge wclk) begin
    if(ce&wen&wmask[1])
      BRAM1[addr] <= din[15:8];
  end

  always @(posedge wclk) begin
    if(ce&wen&wmask[2])
      BRAM2[addr] <= din[23:16];
  end

  always @(posedge wclk) begin
    if(ce&wen&wmask[3])
      BRAM3[addr] <= din[31:24];
  end


  //
  function integer clogb2;
    input integer depth;
      for (clogb2=0; depth>0; clogb2=clogb2+1)
        depth = depth >> 1;
  endfunction

endmodule